const models = require('../models');
const { sys_menu_model: SysMenuModel, sys_user_role_model: SysUserRoleModel, sys_role_menu_model: SysRoleMenuModel } = models;
const DateUtils = require('../utils/dateUtils');
const { Op } = require('sequelize');

class MenuService {
    /**
     * 创建菜单
     * @param {Object} menuData 菜单数据
     */
    async createMenu(menuData) {
        // 根据parentId查询父部门
        let treePath = '0';
        if (menuData.parentId) {
            const parentDept = await SysMenuModel.findOne({
                where: { id: menuData.parentId }
            });
            if (parentDept) {
                treePath = parentDept.treePath ? `${parentDept.treePath},${parentDept.id}` : String(parentDept.id);
            }
        }
        return await SysMenuModel.create({
            ...menuData,
            treePath: treePath,
            params:menuData.params && menuData.params instanceof Object ?JSON.stringify(menuData.params):'',
            createTime: DateUtils.getCurrentTime(),
            updateTime: DateUtils.getCurrentTime()
        });
    }

    /**
     * 更新菜单
     * @param {number} id 菜单ID
     * @param {Object} menuData 菜单数据
     */
    async updateMenu(id, menuData) {
        const existingMenu = await SysMenuModel.findOne({
            where: { id }
        });
        if (!existingMenu) {
            throw new Error('菜单数据不存在');
        }

        await existingMenu.update({
            ...menuData,
            update_time: DateUtils.getCurrentTime()
        });

        return existingMenu;
    }

    /**
     * 删除菜单
     * @param {number} id 菜单ID
     */
    async deleteMenu(id) {
        const menu = await SysMenuModel.findByPk(id);
        if (!menu) {
            throw new Error('菜单数据不存在');
        }

        // 使用事务确保数据一致性
        const t = await models.sequelize.transaction();
        try {
            // 删除角色菜单关联数据
            await SysRoleMenuModel.destroy({
                where: { menuId: id },
                transaction: t
            });

            // 删除菜单
            await menu.destroy({ transaction: t });

            await t.commit();
        } catch (error) {
            await t.rollback();
            throw error;
        }
    }

    /**
     * 获取菜单详情
     * @param {number} id 菜单ID
     */
    async getMenuById(id) {
        return await SysMenuModel.findOne({
            where: { id}
        });
    }


    /**
     * 获取所有菜单列表
     * @param {Object} query 查询条件
     */
    async getMenuTree(query = {}) {
        const { keywords , status } = query;
        const where = { };
        let allMenus = [];

        // 如果有查询条件，先查询匹配的菜单
        if (keywords  || status !== undefined) {
            const matchedMenus = await SysMenuModel.findAll({
                where: {
                    ...where,
                    ...(keywords  && { name: { [Op.like]: `%${keywords }%` } }),
                    ...(status !== undefined && { status })
                },
                order: [['sort', 'ASC'], ['create_time', 'DESC']]
            });

            // 收集所有匹配菜单的ID和上级菜单ID
            const menuIds = new Set();
            matchedMenus.forEach(menu => {
                menuIds.add(menu.id);
                if (menu.treePath) {
                    menu.treePath.split(',').forEach(pid => menuIds.add(pid));
                }
            });

            // 查询所有相关菜单（包括匹配的菜单和它们的上级菜单）
            allMenus = await SysMenuModel.findAll({
                where: {
                    ...where,
                    id: { [Op.in]: Array.from(menuIds) }
                },
                order: [['sort', 'ASC'], ['create_time', 'DESC']]
            });
        } else {
            // 如果没有查询条件，查询所有菜单
            allMenus = await SysMenuModel.findAll({
                where,
                order: [['sort', 'ASC'], ['create_time', 'DESC']]
            });
        }

        return this.buildMenuTree(allMenus);
    }

    /**
     * 构建菜单树形结构
     * @param {Array} menus 菜单列表
     * @returns {Array} 菜单树形结构
     */
    buildMenuTree(menus) {
        // 使用Map优化查找效率
        const menuMap = new Map();
        
        // 第一步：先将所有节点存入Map
        menus.forEach(menu => {
            const node = menu.toJSON();
            menuMap.set(node.id, node);
        });
        
        // 第二步：构建树形结构
        const tree = [];
        menuMap.forEach(node => {
            const { parentId } = node;
            
            if (parentId == 0) {
                // 根节点直接加入树中
                tree.push(node);
            } else {
                // 将子节点添加到父节点的children数组
                const parentNode = menuMap.get(parentId);
                if (parentNode) {
                    if (!parentNode.children) {
                        parentNode.children = [];
                    }
                    parentNode.children.push(node);
                }
            }
        });
        
        return tree;
    }

    /**
     * 获取Vue3路由格式的菜单树
     * @param {number} userId 用户ID
     */
    async getVueRoutes(userId) {
        

        // 1. 获取用户的角色ID列表
        const userRoles = await SysUserRoleModel.findAll({
            where: { user_id: userId },
            attributes: ['role_id']
        });
        const roleIds = userRoles.map(role => role.role_id);

        // 2. 获取角色的菜单ID列表
        const roleMenus = await SysRoleMenuModel.findAll({
            where: { roleId: roleIds },
            attributes: ['menu_id']
        });
        const menuIds = [...new Set(roleMenus.map(menu => menu.menu_id))];

        // 3. 获取菜单详情
        const menus = await SysMenuModel.findAll({
            where: {
                id: menuIds,
                type: { [Op.in]: [1, 2] }  // 只获取菜单和目录类型
            },
            order: [['sort', 'ASC']]
        });

        // 4. 转换为树形结构
        const menuTree = this.buildMenuTree(menus);

        // 5. 格式化为Vue路由格式
        return this.formatVueRoutes(menuTree);
    }

    /**
     * 将菜单树转换为Vue路由格式
     * @param {Array} menuTree 菜单树
     */
    formatVueRoutes(menuTree) {
        return menuTree.map(menu => {
            const route = {
                path: menu.routePath || '',
                name: menu.routeName || '',
                component: menu.component || '',
                meta: {
                    title: menu.name,
                    icon: menu.icon,
                    hidden: menu.visible === 0,
                    keepAlive: menu.keepAlive === 1,
                    alwaysShow: menu.alwaysShow === 1
                }
            };

            // 处理重定向
            if (menu.redirect) {
                route.redirect = menu.redirect;
            }

            // 处理路由参数
            if (menu.params) {
                try {
                    route.meta.params = JSON.parse(menu.params);
                } catch (e) {
                    throw new Error(`解析路由参数失败: ${e.message}`);
                }
            }

            // 递归处理子路由
            if (menu.children && menu.children.length > 0) {
                route.children = this.formatVueRoutes(menu.children);
            }

            return route;
        });
    }

    /**
     * 获取菜单下拉选项
     * @param {boolean} onlyParent 是否只获取目录和菜单
     */
    async getMenuOptions(onlyParent = false) {
        const where = {};
        
        // 如果onlyParent为true，只查询目录和菜单类型
        if (onlyParent) {
            where.type = { [Op.in]: [1, 2] }; // 1: 目录, 2: 菜单
        }

        const menus = await SysMenuModel.findAll({
            where,
            order: [['sort', 'ASC']]
        });

        return this.buildMenuOptionsTree(menus);
    }

    /**
     * 构建菜单下拉选项树形结构
     * @param {Array} menus 菜单列表
     * @param {number} parentId 父级ID
     */
    buildMenuOptionsTree(menus, parentId = 0) {
        const tree = [];
        menus.forEach(menu => {
            if (menu.parentId == parentId) {
                const node = {
                    value: menu.id,
                    label: menu.name,
                    children: this.buildMenuOptionsTree(menus, menu.id)
                };
                if (node.children.length === 0) {
                    delete node.children;
                }
                tree.push(node);
            }
        });
        return tree;
    }
}

module.exports = new MenuService();